﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Jinjia.Approve.Common.Extensions
{
    /// <summary>
    /// Enumerable扩展类
    /// </summary>
    public static class EnumerableExtension
    {
        public static async Task ForEachAsync<T>(this IEnumerable<T> list, Func<T, Task> func)
        {
            if (func is null) throw new ArgumentNullException(nameof(func));
            foreach (var item in list) await func(item);
        }
        
        public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
        {
            if (action is null) throw new ArgumentNullException(nameof(action));
            foreach (var item in list) action(item);
        }

        /// <summary>
        /// 获取所有父节点
        /// </summary>
        /// <param name="dataContext">数据容器</param>
        /// <param name="childFieldExpression">子字段</param>
        /// <param name="parentFieldExpression">父字段</param>
        /// <param name="childValue">子值</param>
        /// <returns>所有父节点</returns>
        public static IEnumerable<T> GetParents<T>(this IEnumerable<T> dataContext, Expression<Func<T, object>> childFieldExpression, Expression<Func<T, object>> parentFieldExpression, object childValue)
        {
            if (dataContext.IsNullOrEmpty()) throw new ArgumentNullException(nameof(dataContext));
            var childName = childFieldExpression.GetMember().Name;
            var parentName = parentFieldExpression.GetMember().Name;
            var childProInfo = typeof(T).GetProperty(childName);
            var parentProInfo = typeof(T).GetProperty(parentName);
            var current = dataContext.SingleOrDefault(x => childProInfo.GetValue(x).Equals(childValue));
            if (current != null)
            {
                yield return current;
                var parentValue = parentProInfo.GetValue(current);
                var i = 0;
                const int maxEachCount = 100;
                while (true)
                {
                    if (i > maxEachCount) throw new Exception($"出现死循环或超出循环上限（{maxEachCount}），检查最顶层的Parent是否是null或者0");
                    if (parentValue is null) break;
                    var parent = dataContext.SingleOrDefault(x => childProInfo.GetValue(x).Equals(parentValue));
                    if (parent is null) break;
                    yield return parent;
                    parentValue = parentProInfo.GetValue(parent, null);
                    i++;
                }
            }
        }
        
        /// <summary>
        /// 允许Null值的Union
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> UnionWithNull<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            if (first == null || second == null)
                return first ?? second;

            return first.Union(second);
        }

        /// <summary>
        /// 判断是否为null或者空集合
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> source)
        {
            return source == null || !source.Any();
        }

        /// <summary>
        /// 转换long集合
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="sources"></param>
        /// <returns></returns>
        public static IEnumerable<long> ToLong(this IEnumerable<string> sources)
        {
            if (sources.IsNullOrEmpty())
                return default;
            var result = new List<long>();

            foreach (var item in sources)
                result.Add(Convert.ToInt64(item));

            return result;
        }

        /// <summary>
        /// 转换long集合
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="sources"></param>
        /// <returns></returns>
        public static IEnumerable<long> ToLong(this IEnumerable<IEnumerable<string>> sources)
        {
            if (sources.IsNullOrEmpty())
                return default;
            var result = new List<long>();

            foreach (var item in sources)
            {
                var itemResult = item.ToLong();
                if (!itemResult.IsNullOrEmpty())
                    result.AddRange(itemResult);
            }

            return result;
        }

        /// <summary>
        /// 去空,返回默认实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        public static IEnumerable<T> ToDefault<T>(this IEnumerable<T> input)
        {
            if (input == null)
                input = new List<T>();

            return input;
        }

        /// <summary>
        /// 筛选增加默认值
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> WhereOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            return source?.Where(predicate) ?? new List<TSource>();
        }

        /// <summary>
        /// 转成字符串拼装
        /// </summary>
        /// <param name="input"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string ToString(this IEnumerable<string> input, string separator)
        {
            if (input == null)
                return default;

            return string.Join(separator, input);
        }
    }
}
